home *** CD-ROM | disk | FTP | other *** search
Wrap
/**************************************************************************** * * ElementHelpers.c * * functions related to elements * ****************************************************************************/ #include <string.h> #include "ElementHelpers.h" #include "Assertion.h" #include "DocumentADT.h" #include "ElementADT.h" #include "Structs.h" #include "StringUtils.h" static Rect CalculateGroupBounds (ElementReference element); static Rect CalculatePolygonBounds (ElementReference element); /***************************************************************************** * * GetFirstSubElement * * Retrieves the first element in an element’s sub-element list * (skips the list header node). If the sub-element list is empty, NIL is * returned. * *****************************************************************************/ ElementReference GetFirstSubElement(ElementReference element) { ElementList sublist; ElementReference firstsub; firstsub = nil; sublist = GetElementSubElementList(element); if (sublist != nil) firstsub = GetFirstElement(sublist); return firstsub; } /***************************************************************************** * * GetElementByNumber * * Recursively searches an element list looking for a specific element by an * element number. * The element number is a unique number: no two elements in any list * in any document will have the same element number. * *****************************************************************************/ ElementReference GetElementByNumber(ElementList list, unsigned long number) { ElementReference iterator; ElementReference element; element = nil; for (iterator = GetFirstElement(list); (iterator != nil) && (element == nil); iterator = GetNextElement(iterator)) { if (GetElementNumber(iterator) == number) element = iterator; if (element == nil) if (GetFirstSubElement(iterator) != nil) element = GetElementByNumber(GetSubElementList(iterator), number); } return element; } /***************************************************************************** * * GetGroupElementBelongsTo * * Returns the group that contains a specified element. If the element is at * the root of the document's element list nil will be returned. * *****************************************************************************/ ElementReference GetGroupElementBelongsTo(ElementList list, ElementReference element) { ElementReference groupElement = nil; if (IsElementInList(list, element, &groupElement)) // this will recursively search the list and group elements. { if (groupElement == element) // we found it at the root level, so return nil as advertised. dsc groupElement = nil; } return groupElement; } /***************************************************************************** * * IsElementInList * * This function recursively searches lists and Group elements for "element" * * Returns : * * true if found. * groupElement is set to == element for the deepest level * groupElement is set to the group owning the "element" for the next to deepest level * groupElement passes on the result from there on. * * NOTE: If there is only 1 level, and "element" is found, then "element" * is returned. This is useful for GetGroupElementBelongsTo to then check it * and return nil as advertised.dsc * *****************************************************************************/ Boolean IsElementInList(ElementList list, ElementReference element, ElementReference *groupElement) { ElementType elementType; ElementReference tempElement; ElementReference returnedElement = nil; Boolean foundIt = false; *groupElement = nil; tempElement = GetFirstElement(list); // get first element in list if ((tempElement != nil) && (tempElement == element)) // check the first element in the list. { *groupElement = tempElement; // this will flag the previous level to return that group as the result (or if at the root this will flag the root to then return nil). foundIt = true; } while ((tempElement != nil) && (!foundIt)) // go until we the object or the end of the line { elementType = GetElementType(tempElement); if (elementType == kGroup) { if (IsElementInList(GetElementSubElementList(tempElement), element, &returnedElement)) { foundIt = true; if (element == returnedElement) // need to flag so I know that at this level, this is the group element to pass back! *groupElement = tempElement; else *groupElement = returnedElement; // pass on through this element with no changes } } if (!foundIt) { tempElement = GetNextElement(tempElement); // move to the next element and try again if (tempElement == element) { *groupElement = tempElement; // this will flag the previous level to return that group as the result (or if at the root this will flag the root to then return nil). foundIt = true; } } } return foundIt; } //---------------------------------------------------------------------------------- long CountElementsByClass(ElementList list, DescType objectClass) { OSErr error = noErr; long numElements = 0L; ElementReference element = nil; ElementType elementType; if (objectClass == typeWildCard || objectClass == cGraphicObject) { numElements = CountElements(list); } else { ElementType requestedType; error = ConvertObjectClassToElementType(objectClass, &requestedType); element = GetFirstElement(list); while (element != nil) { elementType = GetElementType(element); if (requestedType == elementType) { numElements++; } element = GetNextElement(element); } } return numElements; } //---------------------------------------------------------------------------------- // Note: This does not return the element's unique element number, but instead // it returns the index of that type of element: for instance // it returns 4 when the element is the 4th rectangle in a document long GetIndexForElementType(DocumentReference document, ElementReference element, ElementType elementType) { OSErr error = noErr; Boolean foundIt = false; ElementList list; ElementReference iter; ElementType iterType; long index = 0L; long numElements = 0L; list = GetDocumentElementList(document); // First, how many elements of this type are there? iter = GetFirstElement(list); while (iter != nil) { iterType = GetElementType(iter); if (elementType == typeWildCard || elementType == cGraphicObject || elementType == iterType) { numElements++; } iter = GetNextElement(iter); } // Next, what is the index of the requested element and elementType or objectClass? iter = GetFirstElement(list); while (iter != nil) { iterType = GetElementType(iter); if (elementType == typeWildCard || elementType == cGraphicObject || elementType == iterType) index++; if (iter == element) break; iter = GetNextElement(iter); } if (iter != nil && iter == element) { index = numElements - index + 1; // because element 1 is at the end of the list, not the beginning. } else { index = 0; // This is an invalid number for an index, but technically -1, -2, etc. are valid } // because -1 means the last element, -2 means next-to-last, etc. in AppleScript return index; } //---------------------------------------------------------------------------------- // Note: This does not return the element's unique element number, but instead // it returns the index of that type of element: for instance // it returns 4 when the element is the 4th rectangle in a document long GetIndexForSubElementType(DocumentReference document, ElementReference element, ElementReference subElement, ElementType elementType) { #pragma unused (document) OSErr error = noErr; Boolean foundIt = false; ElementList list = GetSubElementList(element); ElementReference tempElement = nil; long index = 0L; long numElements = 0L; // First, how many elements of this type are there? tempElement = GetFirstElement(list); while (tempElement != nil) { if (elementType == typeWildCard || elementType == cGraphicObject || GetElementType(tempElement) == elementType) { numElements++; } tempElement = GetNextElement(tempElement); } // Next, what is the index of the requested element and elementType? tempElement = GetFirstElement(list); while (tempElement != nil) { if (elementType == typeWildCard || elementType == cGraphicObject || GetElementType(tempElement) == elementType) index++; if (tempElement == subElement) break; tempElement = GetNextElement(tempElement); } if (tempElement != nil && tempElement == subElement) { index = numElements - index + 1; // because element 1 is at the end of the list, not the beginning. } else { index = 0; // This is an invalid number for an index, but technically -1, -2, etc. are valid } // because -1 means the last element, -2 means next-to-last, etc. in AppleScript return index; } //---------------------------------------------------------------------------------- OSErr FindElementByIndex(ElementList list, DescType objectClass, long index, ElementReference *element) { OSErr error = noErr; ElementReference tempElement = nil; ElementType elementType; ElementType requestedType; long i = 1L; long numElements = 0L; Boolean foundIt = false; *element = nil; if (objectClass == typeWildCard || objectClass == cGraphicObject) { numElements = CountElements(list); } else { numElements = CountElementsByClass(list, objectClass); error = ConvertObjectClassToElementType(objectClass, &requestedType); } // Negative indexes are offsets from the END of the element list: // rectangle -1 is the last rectangle, rectangle -2 is the next to last rectangle, etc. if (index < 0) { index = numElements + 1 + index; // convert offset from end of list to offset from beginning of list } index = numElements - index + 1; // because element 1 is at the end of the list, not the beginning. if (index < 1 || index > numElements) error = errAEIllegalIndex; // Find the element of the requested type with the requested index if (error == noErr) { i = 1L; tempElement = GetFirstElement(list); while (tempElement != nil) { elementType = GetElementType(tempElement); if (objectClass == typeWildCard || objectClass == cGraphicObject) { if (i == index) { foundIt = true; break; } i++; } else if (requestedType == elementType) { if (i == index) { foundIt = true; break; } i++; } tempElement = GetNextElement(tempElement); } } // return the element, if found if (error == noErr) { if (foundIt) *element = tempElement; else error = errAENoSuchObject; } return error; } //---------------------------------------------------------------------------------- ElementReference FindElementByUniqueID(ElementList list, long uniqueID) { ElementReference element = nil; Boolean foundIt = false; // Find the element of the requested ID element = GetFirstElement(list); while (element != nil) { if (GetElementNumber(element) == uniqueID) { foundIt = true; break; } element = GetNextElement(element); } if (foundIt == false) element = nil; return element; } //---------------------------------------------------------------------------------- // Convert AppleEvent class to elementType code OSErr ConvertObjectClassToElementType(const DescType objectClass, ElementType *elementType) { OSErr error = noErr; switch (objectClass) { case cOval: *elementType = kQDOval; break; case cPolygon: *elementType = kQDPolygon; break; case cRectangle: *elementType = kQDRect; break; case cRoundedRectangle: *elementType = kQDRoundRect; break; case cGraphicLine: *elementType = kQDLine; break; case cGraphicObject: case typeWildCard: *elementType = (ElementType) typeWildCard; break; case cGroupedGraphic: *elementType = kGroup; break; default: error = errAECantHandleClass; break; } return error; } //---------------------------------------------------------------------------------- // Convert an elementType code to AppleEvent class OSErr ConvertElementTypeToObjectClass(const ElementType elementType, DescType *objectClass) { OSErr error = noErr; switch (elementType) { case kQDOval: *objectClass = cOval; break; case kQDPolygon: *objectClass = cPolygon; break; case kQDRect: *objectClass = cRectangle; break; case kQDRoundRect: *objectClass = cRoundedRectangle; break; case kQDLine: *objectClass = cGraphicLine; break; case kGroup: *objectClass = cGroupedGraphic; break; case kUnknownElement: default: error = errAECantHandleClass; break; } return error; } // --------------------------------------------------------------------------- void PopulateElementWithDefaultData(ElementReference element) { RGBColor black = {0x0000, 0x0000, 0x0000}; RGBColor white = {0xFFFF, 0xFFFF, 0xFFFF}; Point ovalSize = { 20, 20}; Rect bounds = { 0, 0, 100,100}; Point p1 = { 0, 0}; Point p2 = {100, 100}; SetElementBoundingBox(element, bounds); SetElementStrokePenHeight(element, 1); SetElementStrokePenWidth(element, 1); SetElementStrokeColor(element, black); SetElementFillColor(element, white); SetElementRoundRectOvalSize(element, ovalSize); SetElementLineBeginPoint(element, p1); SetElementLineEndPoint(element, p2); } #pragma mark - /***************************************************************************** * * CalculateElementBounds * * Public function to get the bounds of both simple and complex objects * *****************************************************************************/ Rect CalculateElementBounds(ElementReference element) { Rect objectBounds; Point p1; Point p2; switch (GetElementType(element)) { case kQDPolygon: objectBounds = CalculatePolygonBounds(element); break; case kQDRect: case kQDRoundRect: case kQDOval: objectBounds = GetElementBoundingBox(element); break; case kQDLine: p1 = GetElementLineBeginPoint(element); p2 = GetElementLineEndPoint(element); objectBounds.top = min(p1.v, p2.v); objectBounds.left = min(p1.h, p2.h); objectBounds.bottom = max(p1.v, p2.v); objectBounds.right = max(p1.h, p2.h); break; case kGroup: objectBounds = CalculateGroupBounds(element); break; default: Assert(kAssertAlways, "Unknown object in CalculateElementBounds"); break; } Assert(objectBounds.top <= objectBounds.bottom, "IMAGING: CalculateElementBounds said that top is greater than bottom"); Assert(objectBounds.left <= objectBounds.right, "IMAGING: CalculateElementBounds said that left is greater than right"); return objectBounds; } /***************************************************************************** * * CalculateGroupBounds * * walk the subElementList and Union all the visible elements bounding boxes together * groupBounds being passed to this function should be set to an empty rectangle * *****************************************************************************/ static Rect CalculateGroupBounds(ElementReference element) { ElementReference iterator; Rect groupBounds = {0, 0, 0, 0}; Rect objectBounds; ElementList list; list = GetSubElementList(element); for (iterator = GetFirstElement(list); iterator != nil; iterator = GetNextElement(iterator)) { if (GetElementType(iterator) == kGroup) objectBounds = CalculateGroupBounds(iterator); else objectBounds = CalculateElementBounds(iterator); if(EmptyRect(&groupBounds)) groupBounds = objectBounds; else UnionRect(&groupBounds, &objectBounds, &groupBounds); } return groupBounds; } /***************************************************************************** * * CalculatePolygonBounds * * Polygons draw outside of their bounding box (go figure!) so we add the * pen size to the right and bottom side of the bounding box * *****************************************************************************/ static Rect CalculatePolygonBounds(ElementReference element) { Rect objectBounds = {0, 0, 0, 0}; PolyHandle polygon; short strokeWidth; short strokeHeight; polygon = GetElementPolygon(element); if (polygon != nil) { objectBounds = (**polygon).polyBBox; strokeWidth = GetElementStrokePenWidth(element); if(strokeWidth < 1) strokeWidth = 1; objectBounds.right += strokeWidth; strokeHeight = GetElementStrokePenWidth(element); if(strokeHeight < 1) strokeHeight = 1; objectBounds.bottom += strokeHeight; } return objectBounds; }